﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Facebook;
using System.Net;
using System.IO;
using System.Threading;
using System.Windows.Threading;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using FBApp.Classes;


namespace FBApp.Classes
{
    public class FacebookClient
    {
        //Authentication
        private FacebookAPI _facebookAPI = new FacebookAPI();
        private string _token = "";
        private bool _authenticated = false;        
        private WebBrowser _webBrowser;

        //Notifications
        private Notifier _notifier;
        private static int sleepTime = 300000;

        private BackgroundWorker notificationThread = new BackgroundWorker();
        private bool firstTimeCheck = true;
        private bool receiveNewsFeedNotifications = true;
        private bool receiveNotifications = true;
        private bool receiveWallFeedNotifications = true;
        private bool receiveMessageNotifications = true;

        private NewsFeed newsFeed;
        private Notifications notificationFeed;
        private WallFeed wallFeed;
        private Messages messageFeed;

        private string _profileID = "";

        public FacebookClient(Notifier notifier, WebBrowser webBrowser)
        {
            this._notifier = notifier;
            this._webBrowser = webBrowser;

            if (!Directory.Exists("Resources/Images/cache"))
            {
                Directory.CreateDirectory("Resources/Images/cache");               
            }
           // clearCache();
        }       

        //Destructor method
        public void Dispose()
        {
            //Stop all threads
        }

        //Authentication
        public void Authenticate(string url)
        {
            FBAuthentication fba = new FBAuthentication();
            _token = fba.webAuthenticate(url);
            if (!_token.Equals(""))
            {
                _authenticated = true;
                _facebookAPI.AccessToken = _token;
                JSONObject me = _facebookAPI.Get("/me");
                Dictionary<string, JSONObject> dictionary = me.Dictionary;

                _profileID = dictionary["id"].ToDisplayableString();                
            }
        }

        //Accessor methods
        public bool IsAuthenticated()
        {
            return _authenticated;
        }

        public string getToken()
        {
            return _token;
        }

        public string getProfileID()
        {
            return _profileID;
        }

        public Notifier getNotifier()
        {
            return _notifier;
        }

        public FacebookAPI getFacebookAPI()
        {
            return _facebookAPI;
        }

        //Mutator methods
        public void setNewsFeed(NewsFeed newsFeed)
        {
            this.newsFeed = newsFeed;
        }

        public void setNotificationFeed(Notifications notificationFeed)
        {
            this.notificationFeed = notificationFeed;
        }

        public void setWallFeed(WallFeed wallFeed)
        {
            this.wallFeed = wallFeed;
        }

        public void setMessageFeed(Messages messageFeed)
        {
            this.messageFeed = messageFeed;
        }

        //Methods
		public void postStatus(string status)
        {            
            Dictionary<string,string> arguments = new Dictionary<string,string>();

            arguments["message"] = status;
              
            _facebookAPI.Post("/me/feed",arguments);
        }

        public void clearCache()
        {
            if (Directory.Exists("Resources/Images/cache"))
            {
                String[] files = Directory.GetFiles("Resources/Images/cache");
                for (int k = 0; k < files.Length; k++)
                {
                    File.Delete(files[k]);
                }
            }
        }
		
        public ImageSource getProfilePicture()
        {
            if (IsAuthenticated())
            {
                JSONObject me = _facebookAPI.Get("/me");
                Dictionary<string, JSONObject> dictionary = me.Dictionary;

                string urlString = "http://graph.facebook.com/" + dictionary["id"].ToDisplayableString() + "/picture";

                BitmapImage bi =  new BitmapImage();
                
                Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                {
                    if (File.Exists("Resources/Images/cache/" + dictionary["id"].ToDisplayableString() + ".jpg"))
                    {
                        
                        bi = new BitmapImage();
                        bi.BeginInit();
                        bi.UriSource = new Uri("Resources/Images/cache/" + dictionary["id"].ToDisplayableString() + ".jpg", UriKind.Relative);
                        bi.CacheOption = BitmapCacheOption.OnLoad;
                        bi.EndInit();
                        double t = bi.Width;                                                
                    }
                    else
                    {                        
                        bi = new BitmapImage(new Uri(urlString, UriKind.Absolute));
                        bi.CacheOption = BitmapCacheOption.OnLoad;
                        
                        bi.DownloadCompleted += delegate
                        {
                            FileStream stream = new FileStream("Resources/Images/cache/" + dictionary["id"].ToDisplayableString() + ".jpg", FileMode.OpenOrCreate);
                            JpegBitmapEncoder jbe = new JpegBitmapEncoder();
                            jbe.Frames.Add(BitmapFrame.Create(bi));
                            jbe.Save(stream);
                            stream.Flush();
                            stream.Close();                            
                        };
                    }                    
                }));
                return bi;
            }
            return null;
        }

        public void updateNotifications()
        {
            List<JSONObject> tempFeed;

            //Notifications
            if (receiveNotifications)
            {
                try
                {
                    tempFeed = notificationFeed.updateNotificationFeed(getToken());
                    for (int k = 0; k < tempFeed.Count; k++)
                    {
                        notificationFeed.addNotificationFeedItem(tempFeed[k]);
                    }

                    if (!firstTimeCheck)
                    {
                        for (int k = 0; k < tempFeed.Count; k++)
                        {
                            if (!tempFeed[k].Dictionary["title_text"].ToDisplayableString().Equals(""))
                            {
                                _notifier.displayNotification(tempFeed[k].Dictionary["title_text"].ToDisplayableString());
                                Thread.Sleep(5000);
                            }
                        }
                    }
                    notificationFeed.refreshUI();
                }
                catch (FacebookAPIException ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }

            //News Feed
            if (receiveNewsFeedNotifications)
            {
                try
                {
                    tempFeed = newsFeed.updateNewsFeed();
                    for (int k = 0; k < tempFeed.Count; k++)
                    {
                        newsFeed.addNewsFeedItem(tempFeed[k]);
                    }

                    if (!firstTimeCheck)
                    {
                        for (int k = 0; k < tempFeed.Count; k++)
                        {
                            if (!tempFeed[k].Dictionary["id"].ToDisplayableString().Equals(""))
                            {
                                if (tempFeed[k].Dictionary.Keys.Contains("message"))
                                {
                                    _notifier.displayNewsFeedNotification(tempFeed[k].Dictionary["from"].Dictionary["id"].ToDisplayableString(), tempFeed[k].Dictionary["from"].Dictionary["name"].ToDisplayableString(), tempFeed[k].Dictionary["message"].ToDisplayableString());
                                    Thread.Sleep(5000);
                                }
                            }
                        }
                    }

                    newsFeed.refreshUI();
                }
                catch (FacebookAPIException ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }

            //Wall Feed
            if (receiveWallFeedNotifications)
            {
                try
                {
                    tempFeed = wallFeed.updateWallFeed();
                    for (int k = 0; k < tempFeed.Count; k++)
                    {
                        wallFeed.addWallFeedItem(tempFeed[k]);
                    }

                    if (!firstTimeCheck)
                    {
                        for (int k = 0; k < tempFeed.Count; k++)
                        {
                            if (!tempFeed[k].Dictionary["id"].ToDisplayableString().Equals(""))
                            {
                                if (tempFeed[k].Dictionary.Keys.Contains("message"))
                                {
                                    _notifier.displayNewsFeedNotification(tempFeed[k].Dictionary["from"].Dictionary["id"].ToDisplayableString(), tempFeed[k].Dictionary["from"].Dictionary["name"].ToDisplayableString(), tempFeed[k].Dictionary["message"].ToDisplayableString());
                                    Thread.Sleep(5000);
                                }
                            }
                        }
                    }

                    wallFeed.refreshUI();

                }
                catch (FacebookAPIException ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }

            //Messages
            if(receiveMessageNotifications)
            {
                try
                {
                    tempFeed = messageFeed.updateMessageFeed();
                    for (int k = 0; k < tempFeed.Count; k++)
                    {
                        messageFeed.addMessageItem(tempFeed[k]);
                    }

                    if (!firstTimeCheck)
                    {
                        for (int k = 0; k < tempFeed.Count; k++)
                        {
                            if (!tempFeed[k].Dictionary["id"].ToDisplayableString().Equals(""))
                            {
                                string subject = "No Subject";
                                if (tempFeed[k].Dictionary.ContainsKey("subject"))
                                {
                                    subject = tempFeed[k].Dictionary["subject"].ToDisplayableString();
                                }
                                
                                _notifier.displayMessageNotification(tempFeed[k].Dictionary["from"].Dictionary["id"].ToDisplayableString(), subject, tempFeed[k].Dictionary["from"].Dictionary["name"].ToDisplayableString(), tempFeed[k].Dictionary["message"].ToDisplayableString());
                                Thread.Sleep(5000);
                            }
                        }
                    }

                }
                catch (FacebookAPIException ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }

        }

        public void enableNotifications()
        {
            notificationThread.DoWork += new DoWorkEventHandler(notificationThread_DoWork);
            notificationThread.RunWorkerAsync();
        }

        //Events
        void notificationThread_DoWork(object sender, DoWorkEventArgs e)
        {                        
            while (true)
            {
                updateNotifications();
                Thread.Sleep(sleepTime);
                if (firstTimeCheck)
                {
                    firstTimeCheck = false;
                }
            }
        }

    }
}
